/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "PCR_Allocate_fp.h"

#if CC_PCR_Allocate  // Conditional expansion of this file

/*(See part 3 specification)
// Allocate PCR banks
*/
//  Return Type: TPM_RC
//      TPM_RC_PCR              the allocation did not have required PCR
//      TPM_RC_NV_UNAVAILABLE   NV is not accessible
//      TPM_RC_NV_RATE          NV is in a rate-limiting mode
/*
TPM可以支持平台重新分配PCR。 要更改PCR的分配，平台将使用TPM2_PCR_Allocate()。 分配结构对每个实现的散列算法都有一个PCR选择。 
要在一个bank中分配一个PCR，相应的位将在该bank的选择中被设置。

TPM2_PCR_Allocate()修改的PCR分配将在下一个_TPM_Init生效，并一直持续到下一个TPM2_PCR_Allocate()。

    注1：由于RAM的限制,一些实现可能不允许在bank内任意分配PCR。这并没有创建一个部署问题,因为平台预计将能够管理将连接到该平台的TPMs。

如果PCR的属性没有由该TPM的平台特定规范定义，则不能分配PCR。

    注2：PCR的属性包括Startup()初始化值、复位的位置和扩展的位置。

有一个要求是每个哈希算法都有一个bank，但不要求bank有任何PCR(也就是说，bank的所有选择的PCR选择位都可以是CLEAR)。

TPM与不可更改的特定PCR分配一起发布是一个有效的实现。 如果TPM不允许更改分配，那么它将不会实现TPM2_PCR_Allocate()。
————————————————
版权声明：本文为CSDN博主「狂奔的乌龟」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/xy010902100449/article/details/127466441

This command is used to set the desired PCR allocation of PCR and algorithms. This command requires Platform Authorization.

The TPM will evaluate the request and, if sufficient memory is available for the requested allocation, 
the TPM will store the allocation request for use during the next _TPM_Init operation. The PCR allocation in place when this
 command is executed will be retained until the next _TPM_Init. If this command is received multiple times before a _TPM_Init, 
 each one overwrites the previous stored allocation.
This command will only change the allocations of banks that are listed in pcrAllocation.
EXAMPLE 1 If a TPM supports SHA1 and SHA256, then it maintains an allocation for two banks (one of which could be empty). 
If pcrAllocation only has a selector for the SHA1 bank, then only the allocation of the SHA1 bank will be changed and the SHA256
 bank will remain unchanged. To change the allocation of a TPM from 24 SHA1 PCR and no SHA256 PCR to 24 SHA256 PCR and no SHA1 PCR,
the pcrAllocation would have to have two selections: one for the empty SHA1 bank and one for the SHA256 bank with 24 PCR.
If a bank is listed more than once, then the last selection in the pcrAllocation list is the one that the TPM will attempt to allocate.
NOTE 1 This does not mean to imply that pcrAllocation.count can exceed HASH_COUNT, the number of digests implemented in the TPM.
EXAMPLE 2 If HASH_COUNT is 2, pcrAllocation can specify SHA-256 twice, and the second one is used.
However, if SHA_256 is specified three times, the unmarshaling may fail and the TPM may return an error.
此命令用于设置所需的 PCR 分配和算法。 此命令需要平台授权。

TPM 将评估请求，如果有足够的内存可用于请求的分配，TPM 将存储分配请求以在下一个 _TPM_Init 操作期间使用。 执行此命令时的 PCR 分配将保留到下一个 _TPM_Init。 
如果在 _TPM_Init 之前多次收到此命令，则每次都会覆盖先前存储的分配。
此命令只会更改 pcrAllocation 中列出的存储区分配。
示例 1 如果 TPM 支持 SHA1 和 SHA256，那么它会维护两个存储体的分配（其中一个可能是空的）。 如果 pcrAllocation 只有一个 SHA1 bank 的选择器，那么只会改变 
SHA1 bank 的分配，而 SHA256 bank 将保持不变。 要将 TPM 的分配从 24 SHA1 PCR 且无 SHA256 PCR 更改为 24 SHA256 PCR 且无 SHA1 PCR，
pcrAllocation 必须有两种选择：一种用于空 SHA1 库，另一种用于具有 24 PCR 的 SHA256 库。
如果银行被多次列出，那么 pcrAllocation 列表中的最后一个选择是 TPM 将尝试分配的那个。
注 1 这并不意味着 pcrAllocation.count 可以超过 HASH_COUNT，TPM 中实现的摘要数。
示例 2 如果 HASH_COUNT 为 2，则 pcrAllocation 可以指定 SHA-256 两次，并使用第二次。
但是，如果 SHA_256 指定了三次，解组可能会失败并且 TPM 可能会返回错误。

This command shall not allocate more PCR in any bank than there are PCR attribute definitions. The PCR attribute definitions indicate 
how a PCR is to be managed – if it is resettable, the locality for update,
etc. In the response to this command, the TPM returns the maximum number of PCR allowed for any bank.
When PCR are allocated, if DRTM_PCR is defined, the resulting allocation must have at least one bank with the D-RTM PCR allocated. If 
HCRTM_PCR is defined, the resulting allocation must have at least one bank with the HCRTM_PCR allocated. If not, the TPM returns TPM_RC_PCR.
The TPM may return TPM_RC_SUCCESS even though the request fails. This is to allow the TPM to return information about the size needed 
for the requested allocation and the size available. 
If the sizeNeeded parameter in the return is less than or equal to the sizeAvailable parameter, then the
allocationSuccess parameter will be YES. Alternatively, if the request fails, The TPM may return TPM_RC_NO_RESULT.
NOTE 2 An example for this type of failure is a TPM that can only support one bank at a time and cannot support arbitrary distribution 
of PCR among banks.
After this command, TPM2_Shutdown() is only allowed to have a startupType equal to TPM_SU_CLEAR until after the next _TPM_Init.
NOTE 3 Even if this command does not cause the PCR allocation to change, the TPM cannot have its state saved. This is done in order to
 simplify the implementation. There is no need to optimize this command as it is not expected to be used more than once in the lifetime 
 of the TPM (it can be used any number of times but there is no justification for optimization)
该命令不得在任何组中分配多于 PCR 属性定义的 PCR。 PCR 属性定义指示如何管理 PCR——如果它是可重置的，更新的位置，
等。在对该命令的响应中，TPM 返回任何银行允许的最大 PCR 数。
分配 PCR 时，如果定义了 DRTM_PCR，则分配结果必须至少有一个 bank 分配了 D-RTM PCR。 如果定义了 HCRTM_PCR，则结果分配必须至少有一个存储区分配了 HCRTM_PCR。
 如果不是，TPM 返回 TPM_RC_PCR。
即使请求失败，TPM 也可能返回 TPM_RC_SUCCESS。 这是为了允许 TPM 返回有关请求分配所需的大小和可用大小的信息。
如果返回中的 sizeNeeded 参数小于或等于 sizeAvailable 参数，则
allocationSuccess 参数将为 YES。 或者，如果请求失败，TPM 可能会返回 TPM_RC_NO_RESULT。
注 2 此类故障的一个示例是 TPM 一次只能支持一个银行并且不能支持在银行之间任意分配 PCR。
在此命令之后，TPM2_Shutdown() 只允许具有等于 TPM_SU_CLEAR 的 startupType，直到下一个 _TPM_Init 之后。
注 3 即使此命令不会导致 PCR 分配发生变化，TPM 也无法保存其状态。 这样做是为了简化实施。 无需优化此命令，因为它预计在 TPM 的生命周期中不会被使用超过一次
（它可以使用任意次数，但没有理由进行优化）
*/
TPM_RC
TPM2_PCR_Allocate(
    PCR_Allocate_In     *in,            // IN: input parameter list
    PCR_Allocate_Out    *out            // OUT: output parameter list
    )
{
    TPM_RC      result;

    // The command needs NV update.  Check if NV is available.
    // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
    // this point.
    // Note: These codes are not listed in the return values above because it is
    // an implementation choice to check in this routine rather than in a common
    // function that is called before these actions are called. These return values
    // are described in the Response Code section of Part 3.
    RETURN_IF_NV_IS_NOT_AVAILABLE;

// Command Output

    // Call PCR Allocation function.
    result = PCRAllocate(&in->pcrAllocation, &out->maxPCR,
                         &out->sizeNeeded, &out->sizeAvailable);
    if(result == TPM_RC_PCR)
        return result;

    //
    out->allocationSuccess = (result == TPM_RC_SUCCESS);

    // if re-configuration succeeds, set the flag to indicate PCR configuration is
    // going to be changed in next boot
    if(out->allocationSuccess == YES)
        g_pcrReConfig = TRUE;

    return TPM_RC_SUCCESS;
}

#endif // CC_PCR_Allocate